home *** CD-ROM | disk | FTP | other *** search
/ Personal Computer World 2005 October / PCWOCT05.iso / Software / FromTheMag / XAMPP 1.4.14 / xampp-win32-1.4.14-installer.exe / xampp / php / pear / DB / ibase.php < prev    next >
PHP Script  |  2004-10-01  |  26KB  |  785 lines

  1. <?php
  2. /* vim: set expandtab tabstop=4 shiftwidth=4 foldmethod=marker: */
  3. // +----------------------------------------------------------------------+
  4. // | PHP Version 4                                                        |
  5. // +----------------------------------------------------------------------+
  6. // | Copyright (c) 1997-2004 The PHP Group                                |
  7. // +----------------------------------------------------------------------+
  8. // | This source file is subject to version 2.02 of the PHP license,      |
  9. // | that is bundled with this package in the file LICENSE, and is        |
  10. // | available at through the world-wide-web at                           |
  11. // | http://www.php.net/license/2_02.txt.                                 |
  12. // | If you did not receive a copy of the PHP license and are unable to   |
  13. // | obtain it through the world-wide-web, please send a note to          |
  14. // | license@php.net so we can mail you a copy immediately.               |
  15. // +----------------------------------------------------------------------+
  16. // | Author: Sterling Hughes <sterling@php.net>                           |
  17. // | Maintainer: Daniel Convissor <danielc@php.net>                       |
  18. // +----------------------------------------------------------------------+
  19. //
  20. // $Id: ibase.php,v 1.69 2004/06/24 15:24:56 danielc Exp $
  21.  
  22.  
  23. // Bugs:
  24. //  - If dbsyntax is not firebird, the limitQuery may fail
  25.  
  26.  
  27. require_once 'DB/common.php';
  28.  
  29. /**
  30.  * Database independent query interface definition for PHP's Interbase
  31.  * extension.
  32.  *
  33.  * @package  DB
  34.  * @version  $Id: ibase.php,v 1.69 2004/06/24 15:24:56 danielc Exp $
  35.  * @category Database
  36.  * @author   Sterling Hughes <sterling@php.net>
  37.  */
  38. class DB_ibase extends DB_common
  39. {
  40.  
  41.     // {{{ properties
  42.  
  43.     var $connection;
  44.     var $phptype, $dbsyntax;
  45.     var $autocommit = 1;
  46.     var $manip_query = array();
  47.  
  48.     // }}}
  49.     // {{{ constructor
  50.  
  51.     function DB_ibase()
  52.     {
  53.         $this->DB_common();
  54.         $this->phptype = 'ibase';
  55.         $this->dbsyntax = 'ibase';
  56.         $this->features = array(
  57.             'prepare' => true,
  58.             'pconnect' => true,
  59.             'transactions' => true,
  60.             'limit' => false
  61.         );
  62.         // just a few of the tons of Interbase error codes listed in the
  63.         // Language Reference section of the Interbase manual
  64.         $this->errorcode_map = array(
  65.             -104 => DB_ERROR_SYNTAX,
  66.             -150 => DB_ERROR_ACCESS_VIOLATION,
  67.             -151 => DB_ERROR_ACCESS_VIOLATION,
  68.             -155 => DB_ERROR_NOSUCHTABLE,
  69.             88   => DB_ERROR_NOSUCHTABLE,
  70.             -157 => DB_ERROR_NOSUCHFIELD,
  71.             -158 => DB_ERROR_VALUE_COUNT_ON_ROW,
  72.             -170 => DB_ERROR_MISMATCH,
  73.             -171 => DB_ERROR_MISMATCH,
  74.             -172 => DB_ERROR_INVALID,
  75.             -204 => DB_ERROR_INVALID,
  76.             -205 => DB_ERROR_NOSUCHFIELD,
  77.             -206 => DB_ERROR_NOSUCHFIELD,
  78.             -208 => DB_ERROR_INVALID,
  79.             -219 => DB_ERROR_NOSUCHTABLE,
  80.             -297 => DB_ERROR_CONSTRAINT,
  81.             -530 => DB_ERROR_CONSTRAINT,
  82.             -607 => DB_ERROR_NOSUCHTABLE,
  83.             -803 => DB_ERROR_CONSTRAINT,
  84.             -551 => DB_ERROR_ACCESS_VIOLATION,
  85.             -552 => DB_ERROR_ACCESS_VIOLATION,
  86.             -922 => DB_ERROR_NOSUCHDB,
  87.             -923 => DB_ERROR_CONNECT_FAILED,
  88.             -924 => DB_ERROR_CONNECT_FAILED
  89.         );
  90.     }
  91.  
  92.     // }}}
  93.     // {{{ connect()
  94.  
  95.     function connect($dsninfo, $persistent = false)
  96.     {
  97.         if (!DB::assertExtension('interbase')) {
  98.             return $this->raiseError(DB_ERROR_EXTENSION_NOT_FOUND);
  99.         }
  100.         $this->dsn = $dsninfo;
  101.         $dbhost = $dsninfo['hostspec'] ?
  102.                   ($dsninfo['hostspec'] . ':' . $dsninfo['database']) :
  103.                   $dsninfo['database'];
  104.  
  105.         $connect_function = $persistent ? 'ibase_pconnect' : 'ibase_connect';
  106.  
  107.         $params = array();
  108.         $params[] = $dbhost;
  109.         $params[] = $dsninfo['username'] ? $dsninfo['username'] : null;
  110.         $params[] = $dsninfo['password'] ? $dsninfo['password'] : null;
  111.         $params[] = isset($dsninfo['charset']) ? $dsninfo['charset'] : null;
  112.         $params[] = isset($dsninfo['buffers']) ? $dsninfo['buffers'] : null;
  113.         $params[] = isset($dsninfo['dialect']) ? $dsninfo['dialect'] : null;
  114.         $params[] = isset($dsninfo['role'])    ? $dsninfo['role'] : null;
  115.  
  116.         $conn = @call_user_func_array($connect_function, $params);
  117.         if (!$conn) {
  118.             return $this->ibaseRaiseError(DB_ERROR_CONNECT_FAILED);
  119.         }
  120.         $this->connection = $conn;
  121.         if ($this->dsn['dbsyntax'] == 'firebird') {
  122.             $this->features['limit'] = 'alter';
  123.         }
  124.         return DB_OK;
  125.     }
  126.  
  127.     // }}}
  128.     // {{{ disconnect()
  129.  
  130.     function disconnect()
  131.     {
  132.         $ret = @ibase_close($this->connection);
  133.         $this->connection = null;
  134.         return $ret;
  135.     }
  136.  
  137.     // }}}
  138.     // {{{ simpleQuery()
  139.  
  140.     function simpleQuery($query)
  141.     {
  142.         $ismanip = DB::isManip($query);
  143.         $this->last_query = $query;
  144.         $query = $this->modifyQuery($query);
  145.         $result = @ibase_query($this->connection, $query);
  146.         if (!$result) {
  147.             return $this->ibaseRaiseError();
  148.         }
  149.         if ($this->autocommit && $ismanip) {
  150.             @ibase_commit($this->connection);
  151.         }
  152.         // Determine which queries that should return data, and which
  153.         // should return an error code only.
  154.         return $ismanip ? DB_OK : $result;
  155.     }
  156.  
  157.     // }}}
  158.     // {{{ modifyLimitQuery()
  159.  
  160.     /**
  161.      * This method is used by backends to alter limited queries
  162.      * Uses the new FIRST n SKIP n Firebird 1.0 syntax, so it is
  163.      * only compatible with Firebird 1.x
  164.      *
  165.      * @param string  $query query to modify
  166.      * @param integer $from  the row to start to fetching
  167.      * @param integer $count the numbers of rows to fetch
  168.      *
  169.      * @return the new (modified) query
  170.      * @author Ludovico Magnocavallo <ludo@sumatrasolutions.com>
  171.      * @access private
  172.      */
  173.     function modifyLimitQuery($query, $from, $count, $params = array())
  174.     {
  175.         if ($this->dsn['dbsyntax'] == 'firebird') {
  176.             //$from++; // SKIP starts from 1, ie SKIP 1 starts from the first record
  177.                            // (cox) Seems that SKIP starts in 0
  178.             $query = preg_replace('/^\s*select\s(.*)$/is',
  179.                                   "SELECT FIRST $count SKIP $from $1", $query);
  180.         }
  181.         return $query;
  182.     }
  183.  
  184.     // }}}
  185.     // {{{ nextResult()
  186.  
  187.     /**
  188.      * Move the internal ibase result pointer to the next available result
  189.      *
  190.      * @param a valid fbsql result resource
  191.      *
  192.      * @access public
  193.      *
  194.      * @return true if a result is available otherwise return false
  195.      */
  196.     function nextResult($result)
  197.     {
  198.         return false;
  199.     }
  200.  
  201.     // }}}
  202.     // {{{ fetchInto()
  203.  
  204.     /**
  205.      * Fetch a row and insert the data into an existing array.
  206.      *
  207.      * Formating of the array and the data therein are configurable.
  208.      * See DB_result::fetchInto() for more information.
  209.      *
  210.      * @param resource $result    query result identifier
  211.      * @param array    $arr       (reference) array where data from the row
  212.      *                            should be placed
  213.      * @param int      $fetchmode how the resulting array should be indexed
  214.      * @param int      $rownum    the row number to fetch
  215.      *
  216.      * @return mixed DB_OK on success, null when end of result set is
  217.      *               reached or on failure
  218.      *
  219.      * @see DB_result::fetchInto()
  220.      * @access private
  221.      */
  222.     function fetchInto($result, &$arr, $fetchmode, $rownum=null)
  223.     {
  224.         if ($rownum !== null) {
  225.             return $this->ibaseRaiseError(DB_ERROR_NOT_CAPABLE);
  226.         }
  227.         if ($fetchmode & DB_FETCHMODE_ASSOC) {
  228.             if (function_exists('ibase_fetch_assoc')) {
  229.                 $arr = @ibase_fetch_assoc($result);
  230.             } else {
  231.                 $arr = get_object_vars(ibase_fetch_object($result));
  232.             }
  233.             if ($this->options['portability'] & DB_PORTABILITY_LOWERCASE && $arr) {
  234.                 $arr = array_change_key_case($arr, CASE_LOWER);
  235.             }
  236.         } else {
  237.             $arr = @ibase_fetch_row($result);
  238.         }
  239.         if (!$arr) {
  240.             if ($errmsg = @ibase_errmsg()) {
  241.                 return $this->ibaseRaiseError(null, $errmsg);
  242.             } else {
  243.                 return null;
  244.             }
  245.         }
  246.         if ($this->options['portability'] & DB_PORTABILITY_RTRIM) {
  247.             $this->_rtrimArrayValues($arr);
  248.         }
  249.         if ($this->options['portability'] & DB_PORTABILITY_NULL_TO_EMPTY) {
  250.             $this->_convertNullArrayValuesToEmpty($arr);
  251.         }
  252.         return DB_OK;
  253.     }
  254.  
  255.     // }}}
  256.     // {{{ freeResult()
  257.  
  258.     function freeResult($result)
  259.     {
  260.         return @ibase_free_result($result);
  261.     }
  262.  
  263.     // }}}
  264.     // {{{ freeQuery()
  265.  
  266.     function freeQuery($query)
  267.     {
  268.         @ibase_free_query($query);
  269.         return true;
  270.     }
  271.  
  272.     // }}}
  273.     // {{{ numCols()
  274.  
  275.     function numCols($result)
  276.     {
  277.         $cols = @ibase_num_fields($result);
  278.         if (!$cols) {
  279.             return $this->ibaseRaiseError();
  280.         }
  281.         return $cols;
  282.     }
  283.  
  284.     // }}}
  285.     // {{{ prepare()
  286.  
  287.     /**
  288.      * Prepares a query for multiple execution with execute().
  289.      *
  290.      * prepare() requires a generic query as string like <code>
  291.      *    INSERT INTO numbers VALUES (?, ?, ?)
  292.      * </code>.  The <kbd>?</kbd> characters are placeholders.
  293.      *
  294.      * Three types of placeholders can be used:
  295.      *   + <kbd>?</kbd>  a quoted scalar value, i.e. strings, integers
  296.      *   + <kbd>!</kbd>  value is inserted 'as is'
  297.      *   + <kbd>&</kbd>  requires a file name.  The file's contents get
  298.      *                     inserted into the query (i.e. saving binary
  299.      *                     data in a db)
  300.      *
  301.      * Use backslashes to escape placeholder characters if you don't want
  302.      * them to be interpreted as placeholders.  Example: <code>
  303.      *    "UPDATE foo SET col=? WHERE col='over \& under'"
  304.      * </code>
  305.      *
  306.      * @param string $query query to be prepared
  307.      * @return mixed DB statement resource on success. DB_Error on failure.
  308.      */
  309.     function prepare($query)
  310.     {
  311.         $tokens   = preg_split('/((?<!\\\)[&?!])/', $query, -1,
  312.                                PREG_SPLIT_DELIM_CAPTURE);
  313.         $token    = 0;
  314.         $types    = array();
  315.         $newquery = '';
  316.  
  317.         foreach ($tokens as $key => $val) {
  318.             switch ($val) {
  319.                 case '?':
  320.                     $types[$token++] = DB_PARAM_SCALAR;
  321.                     break;
  322.                 case '&':
  323.                     $types[$token++] = DB_PARAM_OPAQUE;
  324.                     break;
  325.                 case '!':
  326.                     $types[$token++] = DB_PARAM_MISC;
  327.                     break;
  328.                 default:
  329.                     $tokens[$key] = preg_replace('/\\\([&?!])/', "\\1", $val);
  330.                     $newquery .= $tokens[$key] . '?';
  331.             }
  332.         }
  333.  
  334.         $newquery = substr($newquery, 0, -1);
  335.         $this->last_query = $query;
  336.         $newquery = $this->modifyQuery($newquery);
  337.         $stmt = @ibase_prepare($this->connection, $newquery);
  338.         $this->prepare_types[(int)$stmt] = $types;
  339.         $this->manip_query[(int)$stmt]   = DB::isManip($query);
  340.         return $stmt;
  341.     }
  342.  
  343.     // }}}
  344.     // {{{ execute()
  345.  
  346.     /**
  347.      * Executes a DB statement prepared with prepare().
  348.      *
  349.      * @param resource  $stmt  a DB statement resource returned from prepare()
  350.      * @param mixed  $data  array, string or numeric data to be used in
  351.      *                      execution of the statement.  Quantity of items
  352.      *                      passed must match quantity of placeholders in
  353.      *                      query:  meaning 1 for non-array items or the
  354.      *                      quantity of elements in the array.
  355.      * @return object  a new DB_Result or a DB_Error when fail
  356.      * @see DB_ibase::prepare()
  357.      * @access public
  358.      */
  359.     function &execute($stmt, $data = array())
  360.     {
  361.         if (!is_array($data)) {
  362.             $data = array($data);
  363.         }
  364.  
  365.         $types =& $this->prepare_types[(int)$stmt];
  366.         if (count($types) != count($data)) {
  367.             $tmp =& $this->raiseError(DB_ERROR_MISMATCH);
  368.             return $tmp;
  369.         }
  370.  
  371.         $i = 0;
  372.         foreach ($data as $key => $value) {
  373.             if ($types[$i] == DB_PARAM_MISC) {
  374.                 /*
  375.                  * ibase doesn't seem to have the ability to pass a
  376.                  * parameter along unchanged, so strip off quotes from start
  377.                  * and end, plus turn two single quotes to one single quote,
  378.                  * in order to avoid the quotes getting escaped by
  379.                  * ibase and ending up in the database.
  380.                  */
  381.                 $data[$key] = preg_replace("/^'(.*)'$/", "\\1", $data[$key]);
  382.                 $data[$key] = str_replace("''", "'", $data[$key]);
  383.             } elseif ($types[$i] == DB_PARAM_OPAQUE) {
  384.                 $fp = @fopen($data[$key], 'rb');
  385.                 if (!$fp) {
  386.                     $tmp =& $this->raiseError(DB_ERROR_ACCESS_VIOLATION);
  387.                     return $tmp;
  388.                 }
  389.                 $data[$key] = fread($fp, filesize($data[$key]));
  390.                 fclose($fp);
  391.             }
  392.             $i++;
  393.         }
  394.  
  395.         array_unshift($data, $stmt);
  396.  
  397.         $res = call_user_func_array('ibase_execute', $data);
  398.         if (!$res) {
  399.             $tmp =& $this->ibaseRaiseError();
  400.             return $tmp;
  401.         }
  402.         /* XXX need this?
  403.         if ($this->autocommit && $this->manip_query[(int)$stmt]) {
  404.             @ibase_commit($this->connection);
  405.         }*/
  406.         if ($this->manip_query[(int)$stmt]) {
  407.             $tmp = DB_OK;
  408.         } else {
  409.             $tmp =& new DB_result($this, $res);
  410.         }
  411.         return $tmp;
  412.     }
  413.  
  414.     /**
  415.      * Free the internal resources associated with a prepared query.
  416.      *
  417.      * @param $stmt The interbase_query resource type
  418.      *
  419.      * @return bool true on success, false if $result is invalid
  420.      */
  421.     function freePrepared($stmt)
  422.     {
  423.         if (!is_resource($stmt)) {
  424.             return false;
  425.         }
  426.         @ibase_free_query($stmt);
  427.         unset($this->prepare_tokens[(int)$stmt]);
  428.         unset($this->prepare_types[(int)$stmt]);
  429.         unset($this->manip_query[(int)$stmt]);
  430.         return true;
  431.     }
  432.  
  433.     // }}}
  434.     // {{{ autoCommit()
  435.  
  436.     function autoCommit($onoff = false)
  437.     {
  438.         $this->autocommit = $onoff ? 1 : 0;
  439.         return DB_OK;
  440.     }
  441.  
  442.     // }}}
  443.     // {{{ commit()
  444.  
  445.     function commit()
  446.     {
  447.         return @ibase_commit($this->connection);
  448.     }
  449.  
  450.     // }}}
  451.     // {{{ rollback()
  452.  
  453.     function rollback()
  454.     {
  455.         return @ibase_rollback($this->connection);
  456.     }
  457.  
  458.     // }}}
  459.     // {{{ transactionInit()
  460.  
  461.     function transactionInit($trans_args = 0)
  462.     {
  463.         return $trans_args ? @ibase_trans($trans_args, $this->connection) : @ibase_trans();
  464.     }
  465.  
  466.     // }}}
  467.     // {{{ nextId()
  468.  
  469.     /**
  470.      * Returns the next free id in a sequence
  471.      *
  472.      * @param string  $seq_name  name of the sequence
  473.      * @param boolean $ondemand  when true, the seqence is automatically
  474.      *                           created if it does not exist
  475.      *
  476.      * @return int  the next id number in the sequence.  DB_Error if problem.
  477.      *
  478.      * @internal
  479.      * @see DB_common::nextID()
  480.      * @access public
  481.      */
  482.     function nextId($seq_name, $ondemand = true)
  483.     {
  484.         $sqn = strtoupper($this->getSequenceName($seq_name));
  485.         $repeat = 0;
  486.         do {
  487.             $this->pushErrorHandling(PEAR_ERROR_RETURN);
  488.             $result =& $this->query("SELECT GEN_ID(${sqn}, 1) "
  489.                                    . 'FROM RDB$GENERATORS '
  490.                                    . "WHERE RDB\$GENERATOR_NAME='${sqn}'");
  491.             $this->popErrorHandling();
  492.             if ($ondemand && DB::isError($result)) {
  493.                 $repeat = 1;
  494.                 $result = $this->createSequence($seq_name);
  495.                 if (DB::isError($result)) {
  496.                     return $result;
  497.                 }
  498.             } else {
  499.                 $repeat = 0;
  500.             }
  501.         } while ($repeat);
  502.         if (DB::isError($result)) {
  503.             return $this->raiseError($result);
  504.         }
  505.         $arr = $result->fetchRow(DB_FETCHMODE_ORDERED);
  506.         $result->free();
  507.         return $arr[0];
  508.     }
  509.  
  510.     // }}}
  511.     // {{{ createSequence()
  512.  
  513.     /**
  514.      * Create the sequence
  515.      *
  516.      * @param string $seq_name the name of the sequence
  517.      * @return mixed DB_OK on success or DB error on error
  518.      * @access public
  519.      */
  520.     function createSequence($seq_name)
  521.     {
  522.         $sqn = strtoupper($this->getSequenceName($seq_name));
  523.         $this->pushErrorHandling(PEAR_ERROR_RETURN);
  524.         $result = $this->query("CREATE GENERATOR ${sqn}");
  525.         $this->popErrorHandling();
  526.  
  527.         return $result;
  528.     }
  529.  
  530.     // }}}
  531.     // {{{ dropSequence()
  532.  
  533.     /**
  534.      * Drop a sequence
  535.      *
  536.      * @param string $seq_name the name of the sequence
  537.      * @return mixed DB_OK on success or DB error on error
  538.      * @access public
  539.      */
  540.     function dropSequence($seq_name)
  541.     {
  542.         $sqn = strtoupper($this->getSequenceName($seq_name));
  543.         return $this->query('DELETE FROM RDB$GENERATORS '
  544.                             . "WHERE RDB\$GENERATOR_NAME='${sqn}'");
  545.     }
  546.  
  547.     // }}}
  548.     // {{{ _ibaseFieldFlags()
  549.  
  550.     /**
  551.      * get the Flags of a Field
  552.      *
  553.      * @param string $field_name the name of the field
  554.      * @param string $table_name the name of the table
  555.      *
  556.      * @return string The flags of the field ("primary_key", "unique_key", "not_null"
  557.      *                "default", "computed" and "blob" are supported)
  558.      * @access private
  559.      */
  560.     function _ibaseFieldFlags($field_name, $table_name)
  561.     {
  562.         $sql = 'SELECT R.RDB$CONSTRAINT_TYPE CTYPE'
  563.                .' FROM RDB$INDEX_SEGMENTS I'
  564.                .'  JOIN RDB$RELATION_CONSTRAINTS R ON I.RDB$INDEX_NAME=R.RDB$INDEX_NAME'
  565.                .' WHERE I.RDB$FIELD_NAME=\'' . $field_name . '\''
  566.                .'  AND UPPER(R.RDB$RELATION_NAME)=\'' . strtoupper($table_name) . '\'';
  567.  
  568.         $result = @ibase_query($this->connection, $sql);
  569.         if (!$result) {
  570.             return $this->ibaseRaiseError();
  571.         }
  572.  
  573.         $flags = '';
  574.         if ($obj = @ibase_fetch_object($result)) {
  575.             @ibase_free_result($result);
  576.             if (isset($obj->CTYPE)  && trim($obj->CTYPE) == 'PRIMARY KEY') {
  577.                 $flags .= 'primary_key ';
  578.             }
  579.             if (isset($obj->CTYPE)  && trim($obj->CTYPE) == 'UNIQUE') {
  580.                 $flags .= 'unique_key ';
  581.             }
  582.         }
  583.  
  584.         $sql = 'SELECT R.RDB$NULL_FLAG AS NFLAG,'
  585.                .'  R.RDB$DEFAULT_SOURCE AS DSOURCE,'
  586.                .'  F.RDB$FIELD_TYPE AS FTYPE,'
  587.                .'  F.RDB$COMPUTED_SOURCE AS CSOURCE'
  588.                .' FROM RDB$RELATION_FIELDS R '
  589.                .'  JOIN RDB$FIELDS F ON R.RDB$FIELD_SOURCE=F.RDB$FIELD_NAME'
  590.                .' WHERE UPPER(R.RDB$RELATION_NAME)=\'' . strtoupper($table_name) . '\''
  591.                .'  AND R.RDB$FIELD_NAME=\'' . $field_name . '\'';
  592.  
  593.         $result = @ibase_query($this->connection, $sql);
  594.         if (!$result) {
  595.             return $this->ibaseRaiseError();
  596.         }
  597.         if ($obj = @ibase_fetch_object($result)) {
  598.             @ibase_free_result($result);
  599.             if (isset($obj->NFLAG)) {
  600.                 $flags .= 'not_null ';
  601.             }
  602.             if (isset($obj->DSOURCE)) {
  603.                 $flags .= 'default ';
  604.             }
  605.             if (isset($obj->CSOURCE)) {
  606.                 $flags .= 'computed ';
  607.             }
  608.             if (isset($obj->FTYPE)  && $obj->FTYPE == 261) {
  609.                 $flags .= 'blob ';
  610.             }
  611.         }
  612.  
  613.         return trim($flags);
  614.     }
  615.  
  616.     // }}}
  617.     // {{{ tableInfo()
  618.  
  619.     /**
  620.      * Returns information about a table or a result set.
  621.      *
  622.      * NOTE: only supports 'table' and 'flags' if <var>$result</var>
  623.      * is a table name.
  624.      *
  625.      * @param object|string  $result  DB_result object from a query or a
  626.      *                                string containing the name of a table
  627.      * @param int            $mode    a valid tableInfo mode
  628.      * @return array  an associative array with the information requested
  629.      *                or an error object if something is wrong
  630.      * @access public
  631.      * @internal
  632.      * @see DB_common::tableInfo()
  633.      */
  634.     function tableInfo($result, $mode = null)
  635.     {
  636.         if (isset($result->result)) {
  637.             /*
  638.              * Probably received a result object.
  639.              * Extract the result resource identifier.
  640.              */
  641.             $id = $result->result;
  642.             $got_string = false;
  643.         } elseif (is_string($result)) {
  644.             /*
  645.              * Probably received a table name.
  646.              * Create a result resource identifier.
  647.              */
  648.              $id = @ibase_query($this->connection,
  649.                                 "SELECT * FROM $result WHERE 1=0");
  650.             $got_string = true;
  651.         } else {
  652.             /*
  653.              * Probably received a result resource identifier.
  654.              * Copy it.
  655.              * Deprecated.  Here for compatibility only.
  656.              */
  657.              $id = $result;
  658.             $got_string = false;
  659.         }
  660.  
  661.         if (!is_resource($id)) {
  662.             return $this->ibaseRaiseError(DB_ERROR_NEED_MORE_DATA);
  663.         }
  664.  
  665.         if ($this->options['portability'] & DB_PORTABILITY_LOWERCASE) {
  666.             $case_func = 'strtolower';
  667.         } else {
  668.             $case_func = 'strval';
  669.         }
  670.  
  671.         $count = @ibase_num_fields($id);
  672.  
  673.         // made this IF due to performance (one if is faster than $count if's)
  674.         if (!$mode) {
  675.             for ($i=0; $i<$count; $i++) {
  676.                 $info = @ibase_field_info($id, $i);
  677.                 $res[$i]['table'] = $got_string ? $case_func($result) : '';
  678.                 $res[$i]['name']  = $case_func($info['name']);
  679.                 $res[$i]['type']  = $info['type'];
  680.                 $res[$i]['len']   = $info['length'];
  681.                 $res[$i]['flags'] = ($got_string) ? $this->_ibaseFieldFlags($info['name'], $result) : '';
  682.             }
  683.         } else { // full
  684.             $res['num_fields']= $count;
  685.  
  686.             for ($i=0; $i<$count; $i++) {
  687.                 $info = @ibase_field_info($id, $i);
  688.                 $res[$i]['table'] = $got_string ? $case_func($result) : '';
  689.                 $res[$i]['name']  = $case_func($info['name']);
  690.                 $res[$i]['type']  = $info['type'];
  691.                 $res[$i]['len']   = $info['length'];
  692.                 $res[$i]['flags'] = ($got_string) ? $this->_ibaseFieldFlags($info['name'], $result) : '';
  693.  
  694.                 if ($mode & DB_TABLEINFO_ORDER) {
  695.                     $res['order'][$res[$i]['name']] = $i;
  696.                 }
  697.                 if ($mode & DB_TABLEINFO_ORDERTABLE) {
  698.                     $res['ordertable'][$res[$i]['table']][$res[$i]['name']] = $i;
  699.                 }
  700.             }
  701.         }
  702.  
  703.         // free the result only if we were called on a table
  704.         if ($got_string) {
  705.             @ibase_free_result($id);
  706.         }
  707.         return $res;
  708.     }
  709.  
  710.     // }}}
  711.     // {{{ ibaseRaiseError()
  712.  
  713.     /**
  714.      * Gather information about an error, then use that info to create a
  715.      * DB error object and finally return that object.
  716.      *
  717.      * @param  integer  $db_errno  PEAR error number (usually a DB constant) if
  718.      *                             manually raising an error
  719.      * @param  string  $native_errmsg  text of error message if known
  720.      * @return object  DB error object
  721.      * @see DB_common::errorCode()
  722.      * @see DB_common::raiseError()
  723.      */
  724.     function &ibaseRaiseError($db_errno = null, $native_errmsg = null)
  725.     {
  726.         if ($native_errmsg === null) {
  727.             $native_errmsg = @ibase_errmsg();
  728.         }
  729.         // memo for the interbase php module hackers: we need something similar
  730.         // to mysql_errno() to retrieve error codes instead of this ugly hack
  731.         if (preg_match('/^([^0-9\-]+)([0-9\-]+)\s+(.*)$/', $native_errmsg, $m)) {
  732.             $native_errno = (int)$m[2];
  733.         } else {
  734.             $native_errno = null;
  735.         }
  736.         // try to map the native error to the DB one
  737.         if ($db_errno === null) {
  738.             if ($native_errno) {
  739.                 // try to interpret Interbase error code (that's why we need ibase_errno()
  740.                 // in the interbase module to return the real error code)
  741.                 switch ($native_errno) {
  742.                     case -204:
  743.                         if (is_int(strpos($m[3], 'Table unknown'))) {
  744.                             $db_errno = DB_ERROR_NOSUCHTABLE;
  745.                         }
  746.                         break;
  747.                     default:
  748.                         $db_errno = $this->errorCode($native_errno);
  749.                 }
  750.             } else {
  751.                 $error_regexps = array(
  752.                     '/[tT]able not found/' => DB_ERROR_NOSUCHTABLE,
  753.                     '/[tT]able .* already exists/' => DB_ERROR_ALREADY_EXISTS,
  754.                     '/validation error for column .* value "\*\*\* null/' => DB_ERROR_CONSTRAINT_NOT_NULL,
  755.                     '/violation of [\w ]+ constraint/' => DB_ERROR_CONSTRAINT,
  756.                     '/conversion error from string/' => DB_ERROR_INVALID_NUMBER,
  757.                     '/no permission for/' => DB_ERROR_ACCESS_VIOLATION,
  758.                     '/arithmetic exception, numeric overflow, or string truncation/' => DB_ERROR_DIVZERO
  759.                 );
  760.                 foreach ($error_regexps as $regexp => $code) {
  761.                     if (preg_match($regexp, $native_errmsg)) {
  762.                         $db_errno = $code;
  763.                         $native_errno = null;
  764.                         break;
  765.                     }
  766.                 }
  767.             }
  768.         }
  769.         $tmp =& $this->raiseError($db_errno, null, null, null, $native_errmsg);
  770.         return $tmp;
  771.     }
  772.  
  773.     // }}}
  774.  
  775. }
  776.  
  777. /*
  778.  * Local variables:
  779.  * tab-width: 4
  780.  * c-basic-offset: 4
  781.  * End:
  782.  */
  783.  
  784. ?>
  785.